#pragma once

#include "Widgets/Widget.h"
#include "Widgets/Mouse/MouseWidget.h"
#include "Widgets/Mouse/MouseDrag.h"
#include "Widgets/Mouse/DragDetector.h"
#include "Math/Math.h"
#include "Event/TextInputEvent.h"

#include "Containers/Containers.h"



// store widget exist in this grid
struct WHENGINE_API SWindowGrid
{
public:
    int32_t Row=0;
    int32_t Column=0;

    TVector<RMouseWidget*> Widgets;
};

class RWindow;
class RKeyboardWidget;

class WHENGINE_API CWidgetTree
{

public:
    CWidgetTree(RWindow* OwnerWindow);

    const SIntPoint GridSize=SIntPoint(150,150);
    SIntPoint GridNum;
    TVector<TVector<std::shared_ptr<SWindowGrid>>>  WindowGrids;
    void UpdateWindowGrids(const SIntPoint& InWindowSize);


    void HoldGrids(RMouseWidget* InWidget);
    void UnHoldGrids(RMouseWidget* InWidget);

    void PostHoldGrids();

    bool ProcessMouseEvent(const SMouseButtonEvent& MouseEvent);
private:
    //return the widget which determine mouse cursor
    TWeakObjectPtr<RMouseWidget> ApplyMouseEvent(const SMouseButtonEvent& MouseEvent,bool& EventCustomed);
public:
    bool ProcessTextInput(const STextInputEvent& BoardkeyEvent);

    bool ProcessKeyboardEvent(const SKeyboardEvent& BoardkeyEvent);

    //relative to window
    SVec2 GetMousePositionInContent()
    {
        return CurrentMousePosition; 
    }
private:
    SVec2 CurrentMousePosition=SVec2(0,0);

public:
    void StartDrag(TSharedObjectPtr<RMouseDrag> InDragging)
    {
        assert(InDragging.IsValid() && "invalid dragging widget");

        //stop drag former widget
        if(Dragging)
        {
            Dragging->StopDrag();
        }

        Dragging=InDragging;
    
        Dragging->StartDrag(this);
    }
    
    void StopDrag()
    {
        if(!Dragging)
        {
            return;
        }
        Dragging->StopDrag();
        Dragging=nullptr;
    }  

private:    
    //it's a static value,because:
    //(1) user only have one mouse to drag at same time
    //(2) user might drag widget from a window to anothor
    static TWeakObjectPtr<RMouseDrag> Dragging;

public:

    static void FocusWidget(TSharedObjectPtr<RKeyboardWidget> InWidget);
    static void UnfocusWidget();
    static bool IsFocused(TSharedObjectPtr<RKeyboardWidget> InWidget);

private:
    static TWeakObjectPtr<RKeyboardWidget> KeyboardFocused;

public:
    RWindow* GetWindow() const;
private:
    RWindow* Owner=nullptr;

public:
    TVector<RMouseWidgetPtr> GetHoveringWidgets()
    {
        return HoveringWidgets;
    }
private:
    TVector<RMouseWidgetPtr> HoveringWidgets;

    void UpdateHorveringWidget(const SIntPoint & InMousePosition);

public:
    void StartDetect(TSharedObjectPtr<RMouseDrag>  InDrag);
    bool IsDetecting()
    {
        return DragDetector!=nullptr && DragDetector->IsDetecting();
    }
protected:
    std::unique_ptr<CDragDetector> DragDetector;

public:
    //create a debug id
    int32_t CreateMouseWidgetDebugID()
    {
        return DebugMouseWidgetID++;
    }

protected:
    //give mouse widget a Id for debug
    //Id is ordered in hold grid sequence
    int32_t DebugMouseWidgetID=0;

    
};